package org.goldenmock.web.server;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.easymock.EasyMock;
import org.easymock.IAnswer;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.util.List;
import java.util.Map;

/**
 * Builder class to simplify construction of the HttpServletResponse, and remove
 * any annoyances regarding streams. Implements IAnswer interface for smooth integration
 * with EasyMock.
 * <p/>
 * TODO: This class should be extended to mirror all fields of the HttpServletResponse.
 *
 * @author Robin Wagenaar
 * @author Arjen van Staalduinen
 */
public class EasyHttpResponse implements IAnswer<EasyHttpResponse> {

    private String content, contentType;
    private int httpCode;
    private Map<String, String> headers;
    private Map<String, Object> variables;
    private List<String> returningRequestHeaders;

    /**
     * This is a hook to make custom rendering of the response possible. Comes in handy when external
     * templating engines are used for substituting variables in the content body. But it may also be
     * used to manipulate the EasyHttpResponse in other ways I have not yet thought of. Simply define a
     * guava function to do the rendering.
     * <p/>
     * RenderFunction: Raw EasyHttpResponse goes in, rendered EasyHttpResponse comes out.
     */
    private Function<EasyHttpResponse, EasyHttpResponse> renderFunction;

    public EasyHttpResponse() {
        //sane defaults below.
        this.setContent("");
        this.setContentType("text/plain");
        this.setHttpCode(HttpServletResponse.SC_OK);
        this.setHeaders(Maps.<String, String>newHashMap());
        this.setVariables(Maps.<String, Object>newHashMap());
        this.setReturningHeaders(Lists.<String>newArrayList());
        this.setRenderFunction(new Function<EasyHttpResponse, EasyHttpResponse>() {
            @Override
            public EasyHttpResponse apply(EasyHttpResponse easyHttpResponse) {
                return easyHttpResponse;
            }
        });
    }

    public EasyHttpResponse answer() {
        EasyHttpRequest httpRequest = (EasyHttpRequest) EasyMock.getCurrentArguments()[0];
        for (String returningRequestHeader : returningRequestHeaders) {
            addHeader(returningRequestHeader, httpRequest.getHeader(returningRequestHeader));
        }
        return this;
    }

    public EasyHttpResponse render() {
        return this.renderFunction.apply(this);
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public Map<String, Object> getVariables() {
        return variables;
    }

    public String getContent() {
        return content;
    }

    public int getHttpCode() {
        return httpCode;
    }

    public String getContentType() {
        return contentType;
    }

    public final void setHttpCode(int httpCode) {
        this.httpCode = httpCode;
    }

    public final void setContent(String content) {
        this.content = content;
    }

    public final void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public final void setHeaders(Map<String, String> headers) {
        this.headers = headers;
    }

    public final void addHeader(String key, String value) {
        this.headers.put(key, value);
    }

    public final void addHeaders(Map<String, String> headers) {
        this.headers.putAll(headers);
    }

    public final void setVariables(Map<String, Object> vars) {
        this.variables = vars;
    }

    public final void addVariable(String key, Object val) {
        this.variables.put(key, val);
    }

    public final void addVariables(Map<String, Object> vars) {
        this.variables.putAll(vars);
    }

    public final void setReturningHeaders(List<String> returningHeaders) {
        this.returningRequestHeaders = returningHeaders;
    }

    public final void addReturningHeader(String header) {
        returningRequestHeaders.add(header);
    }

    public final void setRenderFunction(Function<EasyHttpResponse, EasyHttpResponse> renderFunction) {
        this.renderFunction = renderFunction;
    }
}
